home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #3 / Amiga Plus CD - 2002 - No. 03.iso / AmigaPlus / Tools / Development / stunnel-4.04 / _src / src / sselect.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-01-01  |  7.1 KB  |  242 lines

  1. /*
  2.  *   stunnel       Universal SSL tunnel
  3.  *   Copyright (c) 1998-2002 Michal Trojnara <Michal.Trojnara@mirt.net>
  4.  *                 All Rights Reserved
  5.  *
  6.  *   This program is free software; you can redistribute it and/or modify
  7.  *   it under the terms of the GNU General Public License as published by
  8.  *   the Free Software Foundation; either version 2 of the License, or
  9.  *   (at your option) any later version.
  10.  *
  11.  *   This program is distributed in the hope that it will be useful,
  12.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *   GNU General Public License for more details.
  15.  *
  16.  *   You should have received a copy of the GNU General Public License
  17.  *   along with this program; if not, write to the Free Software
  18.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  *   In addition, as a special exception, Michal Trojnara gives
  21.  *   permission to link the code of this program with the OpenSSL
  22.  *   library (or with modified versions of OpenSSL that use the same
  23.  *   license as OpenSSL), and distribute linked combinations including
  24.  *   the two.  You must obey the GNU General Public License in all
  25.  *   respects for all of the code used other than OpenSSL.  If you modify
  26.  *   this file, you may extend this exception to your version of the
  27.  *   file, but you are not obligated to do so.  If you do not wish to
  28.  *   do so, delete this exception statement from your version.
  29.  */
  30.  
  31. #include "common.h"
  32. #include "prototypes.h"
  33.  
  34. #ifdef USE_FORK
  35. static void client_status(void); /* dead children detected */
  36. #endif
  37.  
  38. #ifndef USE_WIN32
  39.  
  40. static int signal_pipe[2];
  41. static char signal_buffer[16];
  42.  
  43. #ifndef USE_WIN32
  44.  
  45. static void sigchld_handler(int sig) { /* SIGCHLD detected */
  46.     int save_errno=errno;
  47.  
  48.     write(signal_pipe[1], signal_buffer, 1);
  49.     signal(SIGCHLD, sigchld_handler);
  50.     errno=save_errno;
  51. }
  52.  
  53. #endif
  54.  
  55. void sselect_init(fd_set *set, int *n) {
  56.     if(pipe(signal_pipe)) {
  57.         ioerror("pipe");
  58.         exit(1);
  59.     }
  60.     alloc_fd(signal_pipe[0]);
  61.     alloc_fd(signal_pipe[1]);
  62. #ifdef FD_CLOEXEC
  63.     /* close the pipe in child execvp */
  64.     fcntl(signal_pipe[0], F_SETFD, FD_CLOEXEC);
  65.     fcntl(signal_pipe[1], F_SETFD, FD_CLOEXEC);
  66. #endif
  67.     FD_SET(signal_pipe[0], set);
  68.     if(signal_pipe[0]>*n)
  69.         *n=signal_pipe[0];
  70.     signal(SIGCHLD, sigchld_handler);
  71. }
  72.  
  73. #endif /* USE_WIN32 */
  74.  
  75. int sselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
  76.         struct timeval *timeout) {
  77.     int retval;
  78.     struct timeval tv;
  79.  
  80.     do { /* Skip "Interrupted system call" errors */
  81.         if(timeout) {
  82.             memcpy(&tv, timeout, sizeof(struct timeval));
  83.             retval=select(n, readfds, writefds, exceptfds, &tv);
  84.         } else { /* No timeout - main loop */
  85.             retval=select(n, readfds, writefds, exceptfds, NULL);
  86. #ifndef USE_WIN32
  87.             if(retval>0 && FD_ISSET(signal_pipe[0], readfds)) {
  88.                 /* Empty the pipe */
  89.                 read(signal_pipe[0], signal_buffer, sizeof(signal_buffer));
  90. #ifdef USE_PTHREAD
  91.                 exec_status(); /* Report status of 'exec' process */
  92. #endif /* USE_PTHREAD */
  93. #ifdef USE_FORK
  94.                 client_status(); /* Report status of client process */
  95. #endif /* USE_FORK */
  96.             }
  97. #endif /* USE_WIN32 */
  98.         }
  99.     } while(retval<0 && get_last_socket_error()==EINTR);
  100.     return retval;
  101. }
  102.  
  103. int waitforsocket(int fd, int dir, int timeout) {
  104.     /* dir: 0 for read, 1 for write */
  105.     struct timeval tv;
  106.     fd_set set;
  107.     int ready;
  108.  
  109.     log(LOG_DEBUG, "waitforsocket: FD=%d, DIR=%s", fd, dir ? "write" : "read");
  110.     FD_ZERO(&set);
  111.     FD_SET(fd, &set);
  112.     tv.tv_sec=timeout;
  113.     tv.tv_usec=0;
  114.     ready=sselect(fd+1, dir ? NULL : &set, dir ? &set : NULL, NULL, &tv);
  115.     switch(ready) {
  116.     case -1:
  117.         sockerror("waitforsocket");
  118.         break;
  119.     case 0:
  120.         log(LOG_DEBUG, "waitforsocket: timeout");
  121.         break;
  122.     case 1:
  123.         log(LOG_DEBUG, "waitforsocket: ok");
  124.         break;
  125.     default:
  126.         log(LOG_INFO, "waitforsocket: unexpected result");
  127.     }
  128.     return ready;
  129. }
  130.  
  131. #ifdef USE_FORK
  132. static void client_status(void) { /* dead children detected */
  133.     int pid, status;
  134.  
  135. #ifdef HAVE_WAIT_FOR_PID
  136.     while((pid=wait_for_pid(-1, &status, WNOHANG))>0) {
  137.         num_clients--; /* one client less */
  138. #else
  139.     if((pid=wait(&status))>0) {
  140.         num_clients--; /* one client less */
  141. #endif
  142. #ifdef WIFSIGNALED
  143.         if(WIFSIGNALED(status)) {
  144.             log(LOG_DEBUG, "Process %d terminated on signal %d (%d left)",
  145.                 pid, WTERMSIG(status), num_clients);
  146.         } else {
  147.             log(LOG_DEBUG, "Process %d finished with code %d (%d left)",
  148.                 pid, WEXITSTATUS(status), num_clients);
  149.         }
  150.     }
  151. #else
  152.         log(LOG_DEBUG, "Process %d finished with code %d (%d left)",
  153.             pid, status, num_clients);
  154.     }
  155. #endif
  156. }
  157. #endif
  158.  
  159. #ifndef USE_WIN32
  160. void exec_status(void) { /* dead local ('exec') process detected */
  161.     int pid, status;
  162.  
  163. #ifdef HAVE_WAIT_FOR_PID
  164.     while((pid=wait_for_pid(-1, &status, WNOHANG))>0) {
  165. #else
  166.     if((pid=wait(&status))>0) {
  167. #endif
  168. #ifdef WIFSIGNALED
  169.         if(WIFSIGNALED(status)) {
  170.             log(LOG_INFO, "Local process %d terminated on signal %d",
  171.                 pid, WTERMSIG(status));
  172.         } else {
  173.             log(LOG_INFO, "Local process %d finished with code %d",
  174.                 pid, WEXITSTATUS(status));
  175.         }
  176. #else
  177.         log(LOG_INFO, "Local process %d finished with status %d",
  178.             pid, status);
  179. #endif
  180.     }
  181. }
  182. #endif /* !defined USE_WIN32 */
  183.  
  184. int fdprintf(CLI *c, int fd, const char *format, ...) {
  185.     va_list arglist;
  186.     char line[STRLEN], logline[STRLEN];
  187.     char crlf[]="\r\n";
  188.     int len, ptr, written, towrite;
  189.  
  190.     va_start(arglist, format);
  191. #ifdef HAVE_VSNPRINTF
  192.     len=vsnprintf(line, STRLEN, format, arglist);
  193. #else
  194.     len=vsprintf(line, format, arglist);
  195. #endif
  196.     va_end(arglist);
  197.     safeconcat(line, crlf);
  198.     len+=2;
  199.     for(ptr=0, towrite=len; towrite>0; ptr+=written, towrite-=written) {
  200.         if(waitforsocket(fd, 1 /* write */, c->opt->timeout_busy)<1)
  201.             return -1;
  202.         written=writesocket(fd, line+ptr, towrite);
  203.         if(written<0) {
  204.             sockerror("writesocket (fdprintf)");
  205.             return -1;
  206.         }
  207.     }
  208.     safecopy(logline, line);
  209.     safestring(logline);
  210.     log(LOG_DEBUG, " -> %s", logline);
  211.     return len;
  212. }
  213.  
  214. int fdscanf(CLI *c, int fd, const char *format, char *buffer) {
  215.     char line[STRLEN], logline[STRLEN];
  216.     int ptr;
  217.  
  218.     for(ptr=0; ptr<STRLEN-1; ptr++) {
  219.         if(waitforsocket(fd, 0 /* read */, c->opt->timeout_busy)<1)
  220.             return -1;
  221.         switch(readsocket(fd, line+ptr, 1)) {
  222.         case -1: /* error */
  223.             sockerror("readsocket (fdscanf)");
  224.             return -1;
  225.         case 0: /* EOF */
  226.             log(LOG_ERR, "Unexpected socket close (fdscanf)");
  227.             return -1;
  228.         }
  229.         if(line[ptr]=='\r')
  230.             continue;
  231.         if(line[ptr]=='\n')
  232.             break;
  233.     }
  234.     line[ptr]='\0';
  235.     safecopy(logline, line);
  236.     safestring(logline);
  237.     log(LOG_DEBUG, " <- %s", logline);
  238.     return sscanf(line, format, buffer);
  239. }
  240.  
  241. /* End of select.c */
  242.